package w83b.ws;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Iterator;

import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPBodyElement;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;

import w83b.w83bUtilidadesComunes.W83bClsTrazas;

/**
 * 
 * @author lgonzalez
 *
 */
public abstract class W83bBaseWSInterface {
	
	
	private String urlWs; // NOPMD by ifernandez on 5/3/10 2:17 PM
	
	/**
	 * 
	 * @return String URL del servicio web
	 */
	protected abstract String getWebServiceURL();
	
	/**
	 * 
	 */
	public W83bBaseWSInterface(){
		this.urlWs = this.getWebServiceURL();
	}
		
	
	/**
     * Realiza la invocación a un servicio web dada la url, el método los nombres de los parámetros y sus valores
     * @param method Método del servicio web que se va a invocar
     * @param paramNames Array de nombres de los parámetros
     * @param paramValues Array de valores de los parámetros               
     * @return String con la respuesta del servicio web
     * @throws W83bWSInterfaceException excepcion
     */            
		protected  String invoke (String method, String[] paramNames, String[] paramValues) throws W83bWSInterfaceException {
        String rtdo = "";
        W83bClsTrazas.traza(null,"Se invoca el webService: " + method);
        for(int i=0; i < paramNames.length; i++){
        	W83bClsTrazas.traza(null,"paramName: " + paramNames[i] + " paramValue: " + paramValues[i]); 
        }
        try{
            MessageFactory mfactory = MessageFactory.newInstance();
            SOAPMessage message = mfactory.createMessage();
            SOAPPart soapPart = message.getSOAPPart();
            SOAPEnvelope envelope = soapPart.getEnvelope();
            SOAPBody body = envelope.getBody();   
            W83bClsTrazas.traza(null,"SOAP");
            
            Name name = envelope.createName(method, "", "http://www.openuri.org/");
            
            SOAPBodyElement element = body.addBodyElement(name);
            for (int i=0; i < paramNames.length && i < paramValues.length; i++) {
                SOAPElement param = element.addChildElement(envelope.createName( paramNames[i]) );
                param.addTextNode( paramValues[i] );
                W83bClsTrazas.traza(null,"paramNames[i]: "+ paramValues[i]);
            }         
            W83bClsTrazas.traza(null,"servicio web antes de newInstance: ");
            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
            W83bClsTrazas.traza(null,"DEspues del new instance");
            SOAPConnection con = factory.createConnection();
            W83bClsTrazas.traza(null,"despues del create connection");
            W83bClsTrazas.traza(null,this.getRawXML(message));
            SOAPMessage response = con.call(message, this.urlWs);
            W83bClsTrazas.traza(null,"INVOKE después del call: " + this.getRawXML(response));
            W83bClsTrazas.traza(null,"this.urlWs: " + this.urlWs );
            //X45bLongTrazas.mostrarTraza("INVOKE this.urlWs" + this.urlWs);
            W83bClsTrazas.traza(null,"El resultado de la invocacion del servicio web: " + method + " response: " + response);
            if(W83bBaseWSInterface.hasFault(response)){
            	throw new W83bWSInterfaceException(this.getClass().getName(),"Error (SOAP FAULT) en el metodo " + method + " del WS" + this.getClass().getName(),null);
            }else{
            	rtdo = W83bBaseWSInterface.getResultado(response);
            }
            W83bClsTrazas.traza(null,"El resultado de la invocacion del servicio web: " + method + " resultado: " + rtdo + " response: " + response );
            W83bClsTrazas.traza(null,"INVOKE El resultado de la invocacion del servicio web: " + method + " resultado: " + rtdo + " response: " + response );
        }catch(SOAPException e){
        	 W83bClsTrazas.trazaError(null,"W83bBaseWSInterface.invoke Error: " + e, null);
        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocacion del metodo " + method + " del WS" + this.getClass().getName(),e);
        }catch (Exception e) {
        	W83bClsTrazas.trazaError(null,"W83bBaseWSInterface.invoke Error: "+ e , null);
        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocacion del metodo " + method + " del WS" + this.getClass().getName(),e);
		}
        if("fc:JWSError".equals(rtdo)){
        	 W83bClsTrazas.trazaError(null,"INVOKE ERROR ", null);
        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocacion del metodo " + method + " del WS" + this.getClass().getName(),null);
        }
        
        return rtdo;
    }//Fin invoke   
		
		private String getRawXML(SOAPMessage message) throws SOAPException, IOException{
			
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			message.writeTo(out);
			return  new String(out.toByteArray());
		}
		
		/**
	     * Realiza la invocación a un servicio web dada la url, el método los nombres de los parámetros y sus valores
	     * @param method Método del servicio web que se va a invocar
	     * @param paramNames Array de nombres de los parámetros
	     * @param paramValues Array de valores de los parámetros
	     * @param paramAttributes atributos               
	     * @return String con la respuesta del servicio web
	     * @throws W83bWSInterfaceException excepcion
	     */            
			protected  String invoke (String method, String[] paramNames, String[] paramValues, String[] paramAttributes) throws W83bWSInterfaceException {
	        String rtdo = "";
	        W83bClsTrazas.traza(null,"Se invoca el webService: " + method);
	        for(int i=0; i < paramNames.length; i++){
	        	W83bClsTrazas.traza(null, "paramName: " + paramNames[i] + " paramValue: " + paramValues[i]); 
	        }
	        try{
	            MessageFactory mfactory = MessageFactory.newInstance();
	            SOAPMessage message = mfactory.createMessage();
	            SOAPPart soapPart = message.getSOAPPart();
	            SOAPEnvelope envelope = soapPart.getEnvelope();
	            
	            envelope.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
	            
	            SOAPBody body = envelope.getBody();   
	            Name name = envelope.createName(method, "", "http://www.openuri.org/");
	            
	            SOAPBodyElement element = body.addBodyElement(name);
	            for (int i=0; i < paramNames.length && i < paramValues.length; i++) {
	                SOAPElement param = element.addChildElement(envelope.createName( paramNames[i]) );
	                param.addAttribute(envelope.createName("xsi:type"),"xsd:"+paramAttributes[i]+"" );
	                param.addTextNode( paramValues[i] );
	            }         
	            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
	            SOAPConnection con = factory.createConnection();
	            SOAPMessage response = con.call(message, this.urlWs);  
	            if(W83bBaseWSInterface.hasFault(response)){
	            	throw new W83bWSInterfaceException(this.getClass().getName(),"Error (SOAP FAULT) en el metodo " + method + " del WS" + this.getClass().getName(),null);
	            }else{	
	            	rtdo = W83bBaseWSInterface.getResultado(response);
	            }
	            W83bClsTrazas.traza(null,"El resultado de la invocacion del servicio web: " + method + " resultado: " + rtdo);
	        }catch(SOAPException e){
	        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocación del metodo " + method + " del WS" + this.getClass().getName(),e);
	        }
	        
	        return rtdo;
	    }//Fin invoke   
		
		
			/**
			 * @param args argumentos
			 */
		public static void main(String[] args) {
	        try {		
				/* Creamos el mensaje */
				MessageFactory mfactory = MessageFactory.newInstance();
				SOAPMessage message = mfactory.createMessage();
				SOAPPart soapPart = message.getSOAPPart();
				SOAPEnvelope envelope = soapPart.getEnvelope();
		
				/* Cuerpo del mensaje */
				SOAPBody body = envelope.getBody();
						
				envelope.setEncodingStyle("http://schemas.xmlsoap.org/soap/encoding/");
		
				/* Nombre del metodo */	
				Name name = envelope.createName("provincia_getByDesc", "m", "http://www.openuri.org/");
				
				SOAPBodyElement element = body.addBodyElement(name);
		
				/* Parametros del metodo */
				SOAPElement provincias = element.addChildElement(envelope.createName("value"));
				provincias.addAttribute(envelope.createName("xsi:type"),"xsd:string" );
				provincias.addTextNode("");
		
				SOAPElement parents = element.addChildElement(envelope.createName("responseWithParents"));
				/* para mandar un valor null --> parents.addAttribute(envelope.createName("xsi:nil"),"true" ); */
				parents.addAttribute(envelope.createName("xsi:type"),"xsd:boolean" );
				parents.addTextNode("true");
				
				SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
				SOAPConnection con = factory.createConnection();
				
				
				
				/* Invocamos la llamada */
				SOAPMessage response = con.call(message, "http://www.integracion.jakina.ejiedes.net/t17iApiWSWar/t17iApiWS");
						
				/* Volcando los resultados */
				response.writeTo(System.out);
			       } catch (SOAPException e) {
				
			        } catch (java.io.IOException e) {
				
			        }
	     }

		

	    /**
	     * Devuelve un objeto SOAPBodyElement dado un mensaje SOAP
	     * @param response Mensaje SOAP de respuesta          
	     * @return SOAPBodyElement Mensaje como objeto SOAPBodyElement
	     * @throws SOAPException excepcion SOAP
	     */            
	    private static SOAPBodyElement getSOAPBodyElement (SOAPMessage response) throws SOAPException {
	        SOAPBodyElement rtdo = null;
	        Iterator iterator = response.getSOAPPart().getEnvelope().getBody().getChildElements();
	        while (iterator.hasNext()) {
	            Object oUndefined = iterator.next();
	            if (oUndefined instanceof SOAPBodyElement) {
	                rtdo = (SOAPBodyElement) oUndefined;
	                break;
	            }
	        }
	        return rtdo;
	    }//Fin getSOAPBodyElement  
	    
	    /**
	     * Decide si el retorno del webservice contiene un mensaje de error
	     * @param response	SOAPMessage	: Respuesta del WS
	     * @return			boolean		: True si contiene un mesaje de error, false e.o.c.
	     * @throws SOAPException		: Excepcion SOPAP
	     */
	    private static boolean hasFault(SOAPMessage response) throws SOAPException{
	    	return response.getSOAPPart().getEnvelope().getBody().getFault()!=null;
	    }
	    
	    /**
	     * Devuelve un String dado un mensaje SOAP y reemplaza los tags para capturar la respuesta
	     * @param response Mensaje SOAP de respuesta          
	     * @return String Mensaje como String
	     * @throws SOAPException excepcion SOAP
	     */            
	    protected static String getResultado (SOAPMessage response) throws SOAPException {
	    	
	        String rtdo = "";        
	        SOAPBodyElement soapBodyElement = W83bBaseWSInterface.getSOAPBodyElement(response);    
	        //String responseElementName = soapBodyElement.getElementName().toString();        
	        //String resultElementName = responseElementName.replaceAll("m:generateDocumentResponse", "Result");          

	        Iterator iterator = soapBodyElement.getChildElements();               
	        while (iterator.hasNext()) {        	
	       		Object objElement = iterator.next();
	        	if (objElement instanceof SOAPElement) {           	
	        		SOAPElement element = (SOAPElement) objElement;
					rtdo = element.getValue();	
					break;
				}
	        	if (objElement instanceof weblogic.webservice.core.soap.SOAPElementImpl) {           	
	        		weblogic.webservice.core.soap.SOAPElementImpl element = (weblogic.webservice.core.soap.SOAPElementImpl) objElement;
					rtdo = element.getValue();
					break;
				} 
	        }        
	    	return rtdo;
	    }
	    
	    
	    /**
	     * Realiza la invocación a un servicio Servlet dada la url, el método los nombres de los parámetros y sus valores
	     * @param paramNames Array de nombres de los parámetros
	     * @param paramValues Array de valores de los parámetros               
	     * @return String con la respuesta del servicio web
	     * @throws W83bWSInterfaceException excepcion
	     */            
		protected  String invoke (String[] paramNames, String[] paramValues) throws W83bWSInterfaceException {
	        String rtdo = "";
	       
	        HttpClient client = new HttpClient();
	        PostMethod method = new PostMethod(this.urlWs);
	       
	        
	        for(int i=0; i < paramNames.length; i++){	        	 
	        	method.addParameter(paramNames[i],paramValues[i]);	        	
	        	W83bClsTrazas.traza(null, "paramName: " + paramNames[i] + " paramValue: " + paramValues[i]);
	        }
	         
	        W83bClsTrazas.traza(null,"Se invoca el servlet: " + this.urlWs);
	        try {
	            // Execute the method.
	            int statusCode = client.executeMethod(method);

	            if (statusCode != HttpStatus.SC_OK) {
	            	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocacion al servlet: " + method.getStatusLine());
	            }

	            // Read the response body.
	            byte[] responseBody = method.getResponseBody();
	            rtdo = new String(responseBody);
	            // Deal with the response.
	            // Use caution: ensure correct character encoding and is not binary data
	           
          } catch (HttpException e) {
        	  throw new W83bWSInterfaceException(this.getClass().getName(),"Fatal protocol violation: " + e.getMessage(),e);
          } catch (IOException e) {
        	  throw new W83bWSInterfaceException(this.getClass().getName(),"Fatal transport error: " + e.getMessage(),e);
          } finally {
            // Release the connection.
            method.releaseConnection();
          }  
	        
          W83bClsTrazas.traza(null,"El resultado de la invocacion del servlet: " + this.urlWs + " resultado: " + rtdo);
	        
	        return rtdo; 
	    }
		
		
		/**
		 * Realiza la invocación a un servicio web dada la url, el método los nombres de los parámetros y sus valores
	     * @param method Método del servicio web que se va a invocar
	     * @param paramNames Array de nombres de los parámetros
	     * @param paramValues Array de valores de los parámetros     
	     * @param namespaceInArguments decide si el namespace debe incluirse junto con los argumentos         
	     * @return String con la respuesta del servicio web
	     * @throws X45aWSInterfaceException excepcion
	     */            
			protected  String invoke (String headerEnvelope, String security, String method, String[] paramNames, String[] paramValues,boolean namespaceInArguments) throws W83bWSInterfaceException {
	        String rtdo = "";
	        W83bClsTrazas.traza(null,"Se invoca el webService: " + method);
	        W83bClsTrazas.traza(null,"paramNames.length: " + paramNames.length);
	        for(int i=0; i < paramNames.length; i++){
	        	W83bClsTrazas.traza(null,"paramName : " + paramNames[i] + " paramValue: " + paramValues[i]); 
	        }
	        try{
	        	 MimeHeaders mimeHeaders = new MimeHeaders();
	        	 mimeHeaders.addHeader("Content-Type", "text/xml");
	        	
	        	
	            MessageFactory mfactory = MessageFactory.newInstance();
	            
	            StringBuffer sbSOAP = new StringBuffer("");
	          

	            sbSOAP.append("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ws=\""+headerEnvelope+"\">");
	            sbSOAP.append("<soapenv:Header>");
	            sbSOAP.append("<n38>" + security.split("<n38>")[1].split("</n38>")[0] + "</n38>");
	            sbSOAP.append("</soapenv:Header>");
	            sbSOAP.append("<soapenv:Body>");
	            sbSOAP.append("<ws:").append(method).append(">");
	            
	            for (int i=0; i < paramNames.length && i < paramValues.length; i++) {
	            	if(namespaceInArguments){
	            		 sbSOAP.append("<ws:");
	            	}else{
	            		 sbSOAP.append("<");
	            	}
	            	 sbSOAP.append(paramNames[i]).append(">");
	            	 sbSOAP.append(paramValues[i]);
	            	 if(namespaceInArguments){
	            		 sbSOAP.append("</ws:");
	            	}else{
	            		 sbSOAP.append("</");
	            	}
	            	 sbSOAP.append(paramNames[i]).append(">");
	            }
	            sbSOAP.append("</ws:").append(method).append(">");
	            sbSOAP.append("</soapenv:Body>");
	            sbSOAP.append("</soapenv:Envelope>");
	            SOAPMessage message = mfactory.createMessage(mimeHeaders,new ByteArrayInputStream(sbSOAP.toString().getBytes()));
	  
	           
	           
	            SOAPConnectionFactory factory = SOAPConnectionFactory.newInstance();
	            SOAPConnection con = factory.createConnection();
	            W83bClsTrazas.traza(null,message.toString());
	            SOAPMessage response = con.call(message, this.urlWs);  
	            rtdo = W83bBaseWSInterface.getResultado(response);
	            W83bClsTrazas.traza(null,"El resultado de la invocacion del servicio web: " + method + " resultado: " + rtdo);
	        }catch(SOAPException e){
	        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocación del metodo " + method + " del WS" + this.getClass().getName(),e);
	        }catch (Exception e) {
	        	throw new W83bWSInterfaceException(this.getClass().getName(),"Error en la invocación del metodo " + method + " del WS" + this.getClass().getName(),e);
			}
	        return rtdo;
	    }//Fin invoke   	
	        	
	     


		
}
